package com.simple.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.simple.common.exception.ServiceException;
import com.simple.common.message.domain.dto.*;
import com.simple.common.message.domain.entity.Message;
import com.simple.common.message.domain.vo.ListByUserMessageVo;
import com.simple.common.message.domain.vo.ListMessageVo;
import com.simple.common.message.domain.vo.MessageTargetVo;
import com.simple.common.message.domain.vo.NoticeVo;
import com.simple.common.message.service.WebSocketService;
import com.simple.common.utils.StringConvertUtils;
import com.simple.framework.core.auth.JwtContext;
import com.simple.framework.core.domain.vo.PagingVo;
import com.simple.framework.utils.BeanCopyUtils;
import com.simple.system.mapper.MessageMapper;
import com.simple.system.mapper.SysDeptMapper;
import com.simple.system.mapper.SysPostMapper;
import com.simple.system.mapper.SysRoleMapper;
import com.simple.system.service.MessageService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


/**
 * @Description 消息表(Message)表服务实现类
 * @Author xiaoke
 * @Date 2024/8/10 18:00
 * @Version 1.0
 */
@Service("MessageService")
public class MessageServiceImpl implements MessageService {

    private final MessageMapper messageMapper;

    private final WebSocketService webSocketService;

    private final SysDeptMapper sysDeptMapper;
    private final SysRoleMapper sysRoleMapper;
    private final SysPostMapper sysPostMapper;

    public MessageServiceImpl(MessageMapper messageMapper, WebSocketService webSocketService, SysDeptMapper sysDeptMapper, SysRoleMapper sysRoleMapper, SysPostMapper sysPostMapper) {
        this.messageMapper = messageMapper;
        this.webSocketService = webSocketService;
        this.sysDeptMapper = sysDeptMapper;
        this.sysRoleMapper = sysRoleMapper;
        this.sysPostMapper = sysPostMapper;
    }


    @Override
    public PagingVo<ListMessageVo> list(ListMessageDto dto) {
        dto.setPageNum((dto.getPageNum() - 1) * dto.getPageSize());
        List<ListMessageVo> sysListUserVos = messageMapper.selectPagineList(dto);
        return new PagingVo<>(sysListUserVos, messageMapper.selectPagineListCount(dto));
    }

    @Override
    public PagingVo<MessageTargetVo> listMessageTargets(Long mid, ListMessageTargetsDto dto) {
        dto.setPageNum((dto.getPageNum() - 1) * dto.getPageSize());
        List<MessageTargetVo> messageTargetVos = messageMapper.listMessageTargets(mid, dto);
        Long total = messageMapper.listMessageTargetsTotal(mid, dto);
        return new PagingVo<>(messageTargetVos, total);
    }

    @Transactional
    @Override
    public Long create(AddMessageDto dto) {
        Message message = BeanCopyUtils.copyBean(dto, Message.class);
        if(dto.getNoticeType().equals("role") || dto.getNoticeType().equals("post")) {
            message.setNoticeTypeTarget(StringConvertUtils.convertSetLong(dto.getTargetIds()));
        }else if(dto.getNoticeType().equals("dept")) {
            message.setNoticeTypeTarget(String.valueOf(dto.getTargetIds().stream().iterator().next()));
        }
        message.setUserId(JwtContext.getUserId());
        messageMapper.insert(message);
        // 插入消息目标
        insertMessageTarget(dto, message);
        return message.getId();
    }

    @Transactional
    @Override
    public void update(Long id, AddMessageDto dto) {
        Message message = messageMapper.selectById(id);
        if (message == null) {
            throw new ServiceException("消息不存在");
        }
        message.setTitle(dto.getTitle());
        message.setContent(dto.getContent());
        message.setStatus(1);
        message.setMessageType(dto.getMessageType());
        message.setNoticeType(dto.getNoticeType());
        message.setUpdateId(JwtContext.getUserId());
        message.setUpdateTime(LocalDateTime.now());
        if(dto.getNoticeType().equals("role") || dto.getNoticeType().equals("post")) {
            message.setNoticeTypeTarget(StringConvertUtils.convertSetLong(dto.getTargetIds()));
        }else if(dto.getNoticeType().equals("dept")) {
            message.setNoticeTypeTarget(String.valueOf(dto.getTargetIds().stream().iterator().next()));
        }else {
            message.setNoticeTypeTarget(null);
        }
        messageMapper.updateById(message);

        // 删除旧消息目标
        messageMapper.deleteMessageTarget(message.getId());
        insertMessageTarget(dto, message);
    }


    @Transactional
    @Override
    public void delete(Long id) {
        messageMapper.deleteById(id);
    }

    @Override
    public List<ListByUserMessageVo> listByUserMessage(boolean isRead) {
        return messageMapper.listByUserMessage(JwtContext.getUserId(), isRead);
    }

    @Override
    public PagingVo<ListByUserMessageVo> listAllUserMessage(ListAllUserMessageDto dto) {
        dto.setPageNum((dto.getPageNum() - 1) * dto.getPageSize());
        List<ListByUserMessageVo> list = messageMapper.listAllUserMessage(dto, JwtContext.getUserId());
        Long total = messageMapper.listAllUserMessageTotal(dto, JwtContext.getUserId());
        return new PagingVo<>(list, total);
    }

    @Override
    public void read(ReadMessageDto dto) {
        messageMapper.readMessage(JwtContext.getUserId(), dto.getIds(), LocalDateTime.now());
    }

    @Transactional
    @Override
    public void revoked(Long id) {
        Message message = messageMapper.selectById(id);
        if (message == null) {
            throw new ServiceException("消息不存在");
        }
        message.setStatus(0);
        messageMapper.updateById(message);
    }

    /**
     * 插入消息目标
     *
     * @param dto     消息DTO
     * @param message 消息
     */
    private void insertMessageTarget(AddMessageDto dto, Message message) {
        // 通知VO
        NoticeVo notice = getNoticeVo(message);
        if (message.getNoticeType().equals("all")) {
            // 广播排除发布人
            HashSet<Long> excludedIds = new HashSet<>();
            excludedIds.add(JwtContext.getUserId());
            messageMapper.insertMessageAllUser(message.getId(), excludedIds);
            webSocketService.broadcastExcludedUserIds(JSON.toJSONString(notice), excludedIds);
        } else {
            Set<Long> targetIds = getMessageTargetIds(dto.getNoticeType(), dto.getTargetIds());
            if(!targetIds.isEmpty()) {
                // 指定用户
                messageMapper.insertMessageTargetIds(message.getId(), targetIds);
                webSocketService.specifiedUser(targetIds, JSON.toJSONString(notice));
            }

        }
    }

    /**
     * 获取通知VO
     *
     * @param message 消息
     * @return NoticeVo
     */
    private NoticeVo getNoticeVo(Message message) {
        NoticeVo notice = new NoticeVo();
        notice.setContent(message.getContent());
        notice.setType(message.getMessageType());
        notice.setTitle(message.getTitle());
        return notice;
    }

    /**
     * 获取消息通知目标Ids
     *
     * @param type      消息类型
     * @param targetIds 目标Id
     * @return Set<Long>
     */
    private Set<Long> getMessageTargetIds(String type, Set<Long> targetIds) {
        switch (type) {
            case "dept":
                targetIds = sysDeptMapper.selectByDeptIdUserIds(targetIds.iterator().next());
                break;
            case "role":
                targetIds = sysRoleMapper.selectByRoleIdsUserIds(targetIds);
                break;
            case "post":
                targetIds = sysPostMapper.selectByPostIdsUserIds(targetIds);
                break;
        }
        return targetIds;
    }

}

